package com.example.customeview.widget;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Scroller;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

/**
 * @author Caleb_F
 * @description:
 * @date :2020-09-19 14:57
 */
public class MyRecyclerView extends RecyclerView {
    /**
     * 判断是否是横向滑动
     */
    private boolean isMoving;
    /**
     * 最小滑动距离
     */
    private int mTouchSlop;
    /**
     * 速度追踪器
     */
    private VelocityTracker mTracker;
    /**
     * 最小滑动速度
     */
    private static final int MIUM_VEL = 500;
    /**
     * 滑动的动画
     */
    private Scroller mScroller;
    /**
     * recyclerView的item，item的两种状态
     * mMoveView是手指在屏幕上移动时Item的状态
     * mLastView是mMoveView是手指脱离屏幕后item的状态
     */
    private ViewGroup mMoveView;
    private ViewGroup mLastView;
    /**
     *滑动的item的宽度
     */
    private int mWidth;

    private int mFirstX;
    private int mFirstY;
    private int mLastX;

    public MyRecyclerView(@NonNull Context context) {
        this(context, null);

    }

    public MyRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    /**
     * 初始化操作
     *
     * @param context
     */
    private void init(Context context) {
        mScroller = new Scroller(context);
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent e) {
        int x = (int) e.getX();
        int y = (int) e.getY();
        obtainVelocity(e);
        switch (e.getAction()){
            case MotionEvent.ACTION_DOWN:
                if(mScroller.isFinished()){
                    mScroller.abortAnimation();
                }
                mFirstX=x;
                mFirstY=y;
                mLastX=x;
                mMoveView= (ViewGroup) findChildViewUnder(x,y);
                if(mLastView!=null && mLastView.getScrollX()!=0 && mLastView!=mMoveView){
                    closeMenu();
                }
                if(mMoveView!=null && mMoveView.getChildCount()>=2)
                {
                    mWidth= mMoveView.getChildAt(1).getWidth();
                }
                else{
                    mWidth = -1;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                //判断是否是横向滑动
                int moveX = Math.abs(x - mFirstX);
                int moveY = Math.abs(y - mFirstY);
                mTracker.computeCurrentVelocity(1000);
                int xVelocity = Math.abs((int) mTracker.getXVelocity());
                int yVelocity = Math.abs((int) mTracker.getXVelocity());
                boolean isHoritalMove =
                        ((moveX > moveY && moveX >= mTouchSlop) || (xVelocity > yVelocity && xVelocity >= MIUM_VEL))
                                && mWidth != -1
                                && getScrollState() == 0;
                if(isHoritalMove){
                    isMoving = true;
                    return true;
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                releaseVelocity();
                closeMenuNow();
                break;
            default:
                break;
        }
        return super.onInterceptTouchEvent(e);
    }

    @Override
    public boolean onTouchEvent(MotionEvent e) {
        int x = (int) e.getX();
        int y = (int) e.getY();
        obtainVelocity(e);
        switch (e.getAction())
        {
            case MotionEvent.ACTION_MOVE:
                if(isMoving){
                    //拦截下来,跟手滑动，判断左滑的距离和右滑动
                    int dx = mLastX - x;
                    if(dx+mMoveView.getScrollX()<=mWidth && dx+mMoveView.getScrollX()>=0){
                            mMoveView.scrollBy(dx,0);
                    }
                    mLastX=x;
                    return true;
                }
                else{
                    //子类没有能力的点击事件，oninterrupt不拦截
                    //判断是否是横向滑动
                    int moveX = Math.abs(x - mFirstX);
                    int moveY = Math.abs(y - mFirstY);
                    mTracker.computeCurrentVelocity(1000);
                    int xVelocity = Math.abs((int) mTracker.getXVelocity());
                    int yVelocity = Math.abs((int) mTracker.getXVelocity());
                    boolean isHoritalMove =
                            ((moveX > moveY && moveX >= mTouchSlop) || (xVelocity > yVelocity && xVelocity >= MIUM_VEL))
                                    && mWidth != -1
                                    && getScrollState() == 0;
                    if(isHoritalMove){
                        int dx = mLastX - x;
                        if(dx+mMoveView.getScrollX()<=mWidth && dx+mMoveView.getScrollX()>=0){
                            mMoveView.scrollBy(dx,0);
                        }
                        mLastX=x;
                        isMoving = true;
                        return true;
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                //使用scroller完成滑动
                if(isMoving){
                    if(!mScroller.isFinished()){
                        mScroller.abortAnimation();
                        mLastView.scrollTo(mScroller.getFinalX(),0);
                    }
                    mLastView=mMoveView;
                    mTracker.computeCurrentVelocity(1000);
                    int scrollX = mLastView.getScrollX();
                    int xVelocity = (int) mTracker.getXVelocity();
                    if(xVelocity<-MIUM_VEL || scrollX>=mWidth/2)
                    {
                        mScroller.startScroll(scrollX,0,mWidth-scrollX,0,Math.abs(mWidth-scrollX));
                    }
                    else{
                        mScroller.startScroll(scrollX,0,-scrollX,0,Math.abs(scrollX));
                    }
                    invalidate();
                    isMoving=false;
                    return true;
                }
                else if(mLastView!=null && mLastView.getScrollX()!=0){
                    closeMenuNow();
                }
                break;
            default:
                break;
        }
        return super.onTouchEvent(e);
    }

    @Override
    public void computeScroll() {
        //当前的滑动有没有完成
        if (mScroller.computeScrollOffset()) {
            if (isInwindow(mLastView)) {
                //在范围内
                mLastView.scrollTo(mScroller.getCurrX(), 0);
                //界面重新绘制
                invalidate();
            } else {
                mScroller.abortAnimation();
                mLastView.scrollTo(mScroller.getFinalX(), 0);
            }
        }
    }

    /**
     * 判定mLastView是可视范围内
     *
     * @param lastView
     * @return
     */
    private boolean isInwindow(ViewGroup lastView) {
        LayoutManager layoutManager = getLayoutManager();
        boolean isInWindow = false;
        if (layoutManager instanceof LinearLayoutManager) {
            int firstPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
            int lastPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
            int position = layoutManager.getPosition(lastView);
            isInWindow = position <= lastPosition && position >= firstPosition;
        }
        return isInWindow;
    }

    /**
     * 绑定速度追踪器
     */
    private void obtainVelocity(MotionEvent event) {
        if (mTracker == null) {
            mTracker = VelocityTracker.obtain();
        }
        mTracker.addMovement(event);
    }

    /**
     * 释放速度追踪器
     */
    private void releaseVelocity() {
        if (mTracker != null) {
            mTracker.clear();
            mTracker.recycle();
            mTracker = null;
        }
    }


    //关闭菜单
    private void closeMenu() {
        mScroller.startScroll(mLastView.getScrollX(), 0, -mLastView.getScrollX(), 0,
                Math.abs(mLastView.getScrollX()));
        invalidate();
    }

    //立即关闭菜单
    private void closeMenuNow() {
        if (mLastView != null && mLastView.getScrollX() != 0) {
            mLastView.scrollTo(0, 0);
        }
    }
}
